// Copyright 2022 jeff.li. and/or its affiliates.

#pragma once

#include <type_traits>

namespace tbir::runtime {
    namespace {

        template<class...>
        using __my_void_t_for_comparable__ = void;

        template<typename T, typename U, typename = __my_void_t_for_comparable__<>>
        struct is_eq_comparable : std::false_type {
        };
        template<typename T, typename U>
        struct is_eq_comparable<
                T,
                U,
                __my_void_t_for_comparable__<decltype(std::declval<T &>() == std::declval<U &>(), void())>>
                : std::true_type {
        };

        template<typename T, typename U, typename = __my_void_t_for_comparable__<>>
        struct is_lt_comparable : std::false_type {
        };
        template<typename T, typename U>
        struct is_lt_comparable<
                T,
                U,
                __my_void_t_for_comparable__<decltype(std::declval<T &>() < std::declval<U &>(), void())>>
                : std::true_type {
        };

        template<typename T, typename U, typename = __my_void_t_for_comparable__<>>
        struct is_le_comparable : std::false_type {
        };
        template<typename T, typename U>
        struct is_le_comparable<
                T,
                U,
                __my_void_t_for_comparable__<decltype(std::declval<T &>() <= std::declval<U &>(), void())>>
                : std::true_type {
        };

        template<typename T, typename U, typename = __my_void_t_for_comparable__<>>
        struct is_gt_comparable : std::false_type {
        };
        template<typename T, typename U>
        struct is_gt_comparable<
                T,
                U,
                __my_void_t_for_comparable__<decltype(std::declval<T &>() > std::declval<U &>(), void())>>
                : std::true_type {
        };

        template<typename T, typename U, typename = __my_void_t_for_comparable__<>>
        struct is_ge_comparable : std::false_type {
        };
        template<typename T, typename U>
        struct is_ge_comparable<
                T,
                U,
                __my_void_t_for_comparable__<decltype(std::declval<T &>() >= std::declval<U &>(), void())>>
                : std::true_type {
        };

        template<typename T, typename U>
        struct is_comparable {
            static constexpr bool value = is_eq_comparable<T, U>::value && is_lt_comparable<T, U>::value &&
                                          is_gt_comparable<T, U>::value;
        };

    }  // namespace
}  // namespace  tbir::runtime
